package cn.mill.core.modem;

import java.lang.annotation.Annotation;
import java.lang.reflect.Type;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cn.mill.common.Context;
import cn.mill.common.Tag;
import cn.mill.common.annotation.Property;
import cn.mill.common.data.DataCommon;
import cn.mill.common.data.Item;
import cn.mill.common.data.ItemArray;
import cn.mill.core.MillConfig;
import cn.mill.core.Result;
import cn.mill.core.utils.NormUtil;

public class DefaultSpell {
	
	private static final Logger logger = LoggerFactory.getLogger(DefaultSpell.class);
	
	public static DefaultSpell INSTANCE = new DefaultSpell();
	
	public ItemArray resolver(Context context) {
		Object[] ps = context.getParameters();
		if (ps == null) {
			return new ItemArray();
		}
		ItemArray array = new ItemArray(ps.length);
		Annotation[][] pann = context.getParameterAnnotations();
		for (int i = 0; i < ps.length; i++) {
			Annotation[] arr = NormUtil.getParameterAnnotations(i, pann);
			if (arr != null && ps[i] != null) {
				Property property = (Property) NormUtil.getAnnotation(Property.class, arr);
				boolean isJavaBean = !NormUtil.isBaseObject(ps[i]);
				Type type = context.getParameterTypes()[i];
				if (isJavaBean) {
					ObjectSpell objectSpell = (ObjectSpell) MillConfig.getResolver(context.getParameterTypes()[i]);
					ItemArray itemArray = objectSpell.resolver(context, type, ps[i]);
					if (property != null) {
						Item item = new Item();
						item.setName(NormUtil.isEmpty(property.name()) ? property.value() : property.name());
						item.setProperty(property);
						item.setType(ItemArray.class);
						item.setValue(itemArray);
						array.addItem(item);
					} else {
						array.merge(itemArray);
					}
				} else {
					FieldSpell fieldSpell = (FieldSpell) MillConfig.getResolver(context.getParameterTypes()[i]);
					if (property != null) {
						Item item = fieldSpell.resolver(context, NormUtil.isEmpty(property.name()) ? property.value() : property.name(), type, ps[i]);
						item.setProperty(property);
						if (!Tag.BODY.equals(property.tag())) {
							context.addAttachments(item.getName(), item);
						}
						array.addItem(item);
					}
				}
			}
		}
		array.sort();
		logger.debug("[ItemArray size:[" + array.getSize() + "]]");
		return array;
	}
	
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public <T> T builder(Type type, DataCommon<ItemArray> dataCommon) {
		if (dataCommon == null || type == null) {
			logger.error(" DefaultSpell get result fail ,dataCommon is null or type is null");
			return null;
		}
		if (Boolean.TYPE.equals(type)) {
			return (T) new Boolean(dataCommon.isFine());
		}
		Object o = null;
		try {
			ObjectSpell objectSpell = (ObjectSpell) MillConfig.getBuilder(type);
			o = objectSpell.builder(type, dataCommon.getValue());
			if (o instanceof Result) {
				((Result) o).setCode(dataCommon.getCode());
				((Result) o).setException((Exception) dataCommon.getException());
				((Result) o).setFine(dataCommon.isFine());
				((Result) o).setMessage(dataCommon.getMessage());
			}
		} catch (Exception e) {
			logger.error("DefaultSpell-> builder", e);
		}
		return ((T) o);
	}
}
